package com.demo.common.plugin.activerecord.directive;

import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.template.expr.ast.Const;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * #sqlPara 指令方便定义SqlPara  <a href="https://www.jfinal.com/doc/5-13">SqlPara</a>
 * <p>
 * 定义：
 * #runSql(受影响行数返回结果的变量名默认是result, true) 特殊场景：给true参数时代表运行异常时可继续执行
 * 在此是SQL语句，多条用 ;\n 分号加回车符 隔开
 * #end
 * <p>
 */
public class RunSqlDirective extends SqlParaDirective {
    private boolean isRuntimeException = false;

    private void initIsRuntimeException() {
        int k0 = 0;
        if (exprArray == null || exprArray.length == k0) {
            return;
        }
        if (exprArray[k0] instanceof Const) {
            isRuntimeException = ((Const) exprArray[k0]).isTrue();
            return;
        }
        int k1 = 1;
        if (exprArray.length == k1) {
            return;
        }
        if (exprArray[k1] instanceof Const) {
            isRuntimeException = ((Const) exprArray[k1]).isTrue();
        }
    }

    private static final Object[] NULL_PARA_ARRAY = new Object[0];
    @Override
    protected Object getData(SqlPara sqlPara) {
        setDefaultName("result");
        initIsRuntimeException();

        String sql = sqlPara.getSql();
        Object[] paras = sqlPara.getPara();
        //单行SQL
        if (!sql.contains(";")){
            return update(sql, paras);
        }
        String[] sqlArr = sql.replaceAll(";\r\n", ";\n").split(";\n");
        if (sqlArr.length == 1){
            return update(sql, paras);
        }
        //多行SQL
        List<Integer> ret = new ArrayList<>(sqlArr.length);
        int from = 0;
        int to;
        Object[] para;
        for (String s : sqlArr) {
            if (StrKit.isBlank(s)) {
                continue;
            }
            int count = count(s);
            if (count == 0) {
                para = NULL_PARA_ARRAY;
            } else {
                to = from + count;
                para = Arrays.copyOfRange(paras, from, to);
                from = to;
            }
            ret.add(update(s, para));
        }
        return ret;
    }

    private static int count(String s) {
        int to = 0;
        int length = s.length();
        for (int i = 0; i < length; i++) {
            if (s.charAt(i) == '?') {
                to++;
            }
        }
        return to;
    }

    private int update(String sql, Object[] para) {
        if (StrKit.isBlank(sql)){
            return 0;
        }
        try {
            return db().update(sql, para);
        }catch (ActiveRecordException e){
            if (isRuntimeException){
                write(sql);
                write(" 执行失败:");
                write(e.getMessage());
                write(" 。跳过继续执行。\n");
            }else {
                throw e;
            }
        }
        return 0;
    }
}
